/*
 * author      : 吴中勤
 * date        : 2018/8/16
 * description : 负责维护 (moby->SAP) order 的组装
 */

package com.deepexi.adapter.converter.sap.order;

import com.deepexi.adapter.common.StringUtil;
import com.deepexi.adapter.converter.sap.DateFormatConvert;
import com.deepexi.adapter.converter.sap.SapConverterContext;
import com.deepexi.adapter.converter.sap.SapMapConst;
import com.deepexi.adapter.converter.sap.SapMobyMapService;
import com.deepexi.adapter.converter.sap.fund.SapAdapterFund;
import com.deepexi.adapter.converter.sap.fund.SapAdapterFundMapper;
import com.deepexi.adapter.converter.sap.sapdict.*;
import com.deepexi.adapter.facade.moby.request.MobyEventBody;
import com.deepexi.adapter.facade.moby.request.MobyOrderLine;
import com.deepexi.adapter.facade.moby.request.MobyTradeOrder;
import com.deepexi.adapter.facade.moby.request.StockOut;
import com.deepexi.adapter.sdk.sap.dto.order.*;
import com.deepexi.adapter.sdk.sap.exception.SapBizException;
import com.mysql.jdbc.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class OrderAssembler {

    @Autowired
    private SapAdapterOrderMapper orderMapper;

    @Autowired
    private SapAdapterFundMapper fundMapper;

    @Autowired
    private SapAdapterOrderLineMapper lineMapper;

    @Autowired
    private SapConverterContext sapConverterContext;

    @Autowired
    private SapMobyMapService sapMobyMapService;

    @Autowired
    private SapDictService dictService;

    @Autowired
    private Material2ItCatMapper material2ItCatMapper;

    private static final Logger logger = LoggerFactory.getLogger(OrderAssembler.class);

    /**
     * 从需求中创建 Sap订单
     * 比较复杂的逻辑映射
     * 1. 订单类型
     * - - 大客户买车  = Q005
     * - - 整车订单 = 350X
     * - - 精品单独销售 = Q007
     * 2. 销售渠道
     * - - 10 = 销售，整车/随车销售
     * - - 20 = 售后，单独销售
     * 3. 行项目类别关系映射
     * - 根据 moby的sku类别, isFree 来对应到 sap的itemCatalog. 有一张表存储这个映射关系
     */
    public SapOrderRequestBody assembleCreate(MobyEventBody body) throws SapBizException {

        /* 查询是否已经存在, 如果已经存在, 则表示是重复请求 */
        SapAdapterOrder adapterOrder = orderMapper.findOneByMobyOrder(body.getMobyTradeOrder().getId());
        if (null != adapterOrder)
            throw new SapBizException("已经存在此订单的记录, 不进行创建");

        /* 根据body 构建一个 sap请求体 */
        MobyTradeOrder mobyTradeOrder = body.getMobyTradeOrder();
        SapOrderCreateRequestBody sapBody = new SapOrderCreateRequestBody();
        sapBody.setShopCode(mobyTradeOrder.getShopCode());
        sapBody.setScCode(mobyTradeOrder.getScCode());
        sapBody.setWhoPlaceOrder(sapConverterContext.getMemberBP().getBpNum());

        /* 订单类型, 根据字典进行查询 */
        String orderTypeCode = mobyTradeOrder.getOrderTypeCode();
        String sapOrderType = dictService.getSapValueByMoby(SapDictType.ORDER_TYPE_BOTH, orderTypeCode);
        if (null == sapOrderType)
            throw new SapBizException("moby的订单类型代码=" + orderTypeCode + ", 未找到对应的 sap的销售类型");
        sapBody.setOrderType(sapOrderType);

        /* 渠道, 根据字典进行查询 */
        String sapChannel = dictService.getSapValueByMoby(SapDictType.ORDER_TYPE_CHANNEL, orderTypeCode);
        if (null == sapChannel)
            throw new SapBizException("moby的订单类型代码=" + orderTypeCode + ", 未找到对应的 sap的销售渠道");
        sapBody.setSaleChannel(sapChannel);

        /* 车辆内部编码, 如果vehicleCode为空, 表示分车失败, 需要后续流程中进行一次分车 事件:分车 */
        MobyOrderLine vehicleLine = sapMobyMapService.getVehicleLine(body.getFlatTradeOrderLineList());
        if (null != vehicleLine) {
            sapBody.setVechileCode(vehicleLine.getVehicleCode());
        } else {
            sapBody.setVechileCode("");
        }

        /* 贷款三项 hasLoan FirstPay LoanAmount */
        MobyOrderLine loanLine = sapMobyMapService.getConfirmedLoanLine(body.getFlatTradeOrderLineList());
        if (null != loanLine) {
            sapBody.hasLoan();
            sapBody.setFirstPay(loanLine.getDownPayment());
            sapBody.setLoanAmount(loanLine.getLoanAmount());
        } else {
            sapBody.setHasLoan("");
            sapBody.setFirstPay("");
            sapBody.setLoanAmount("");
        }
        sapBody.setRemark(mobyTradeOrder.getRemark());
        sapBody.setMemberId(body.getMobyMember().getId());

        /* 下单时 操作人是C端用户, 这里没有操作人员 */
        sapBody.setOperatorId("");
        sapBody.setMobyOrderId(body.getMobyTradeOrder().getId());

        /* 处理订单行 orderline */
        for (MobyOrderLine mobyLine : body.getFlatTradeOrderLineList()) {
            createFromEachMobyLine(body, sapBody, mobyLine);
        }

        return sapBody;
    }

    /** 组装请求体: 分车 */
    public SapOrderRequestBody assembleLockVehicle(MobyEventBody body) throws SapBizException {

        SapAdapterOrder oldRecord = assureMobyTradeOrderExist(body);
        String mobyTradeOrderId = body.getMobyTradeOrder().getId();

        MobyOrderLine vehicleLine = sapMobyMapService.getVehicleLine(body.getFlatTradeOrderLineList());
        if (null == vehicleLine)
            throw new SapBizException("进行分车, 但没有车辆订单行, moby订单号=" + mobyTradeOrderId);

        if (StringUtils.isNullOrEmpty(vehicleLine.getVehicleCode()))
            throw new SapBizException("进行分车, 但订单行无车辆编码, moby订单号=" + mobyTradeOrderId);

        List<SapAdapterOrderLine> lineList = lineMapper.listByMobyOrder(mobyTradeOrderId);
        SapAdapterOrderLine vehicleLineRecord = sapMobyMapService.getVehicleLineFromRecord(lineList);
        if (null == vehicleLineRecord)
            throw new SapBizException("进行分车, 但Adapter数据库中无此订单车辆行记录, moby订单号=" + mobyTradeOrderId);

        // 正常流程 happy way
        SapLockVehicleRequestBody sapBody = new SapLockVehicleRequestBody();
        sapBody.setShopCode(oldRecord.getShopCode());
        sapBody.setSapOrderNo(oldRecord.getSapOrderNo());
        sapBody.setOrderType(oldRecord.getOrderType());
        sapBody.setVechileCode(vehicleLine.getVehicleCode());
        sapBody.setMemberId(oldRecord.getMemberId());
        sapBody.setOperatorId("");  // 分车是自动的
        sapBody.setMobyOrderId(oldRecord.getMobyOrderId());

        return sapBody;
    }

    /** 组装请求体: 取消分车 */
    public SapOrderRequestBody assembleUnlockVehicle(MobyEventBody body) throws SapBizException {
        String mobyTradeOrderId = body.getMobyTradeOrder().getId();
        return assembleUnlockVehicleById(mobyTradeOrderId);
    }

    /** 组装请求体: 取消分车 */
    public SapOrderRequestBody assembleUnlockVehicleById(String mobyTradeOrderId) throws SapBizException {

        SapAdapterOrder oldRecord = assureMobyTradeOrderExist(mobyTradeOrderId);

        // 正常流程 happy way
        SapUnlockVehicleRequestBody sapBody = new SapUnlockVehicleRequestBody();
        sapBody.setShopCode(oldRecord.getShopCode());
        sapBody.setSapOrderNo(oldRecord.getSapOrderNo());
        sapBody.setOrderType(oldRecord.getOrderType());
        sapBody.setMemberId(oldRecord.getMemberId());
        sapBody.setMobyOrderId(oldRecord.getMobyOrderId());
        sapBody.setOperatorId("");

        return sapBody;
    }

    /** 组装请求体: 金融方案确认 */
    public SapOrderRequestBody assembleLoan(MobyEventBody body) throws SapBizException {
        SapAdapterOrder oldRecord = assureMobyTradeOrderExist(body);
        String mobyTradeOrderId = body.getMobyTradeOrder().getId();

        MobyOrderLine loanLine = sapMobyMapService.getConfirmedLoanLine(body.getFlatTradeOrderLineList());
        if (null == loanLine)
            throw new SapBizException("确认金融, 没有 已确认 的金融订单行" + mobyTradeOrderId);

        List<SapAdapterOrderLine> sapAdapterOrderLineList = lineMapper.listByMobyOrder(mobyTradeOrderId);
        for (SapAdapterOrderLine oneItem : sapAdapterOrderLineList) {
            if (oneItem.getMobyLineId().equals(loanLine.getId())) {
                logger.warn("金融订单行已存在");
                throw new SapBizException("金融订单行已存在, 不需要同步到SAP, 此异常可能由moby多次通知");
            }
        }

        //
        SapLoanConfirmedRequestBody sapBody = new SapLoanConfirmedRequestBody();
        BeanUtils.copyProperties(oldRecord, sapBody);
        sapBody.setMemberId(body.getMobyMember().getId());
        sapBody.setHasLoan(SapOrderRequestBody.HAS_LOAN);
        sapBody.setFirstPay(loanLine.getDownPayment());
        sapBody.setLoanAmount(loanLine.getLoanAmount());
        sapBody.setOperatorId(loanLine.getOperatorId());
        createFromEachMobyLine(body, sapBody, loanLine);

        return sapBody;
    }

    /** 组装请求体: 保险方案确认 */
    public SapOrderRequestBody assembleInsurance(MobyEventBody body) throws SapBizException {
        SapAdapterOrder oldRecord = assureMobyTradeOrderExist(body);
        String mobyTradeOrderId = body.getMobyTradeOrder().getId();

        List<MobyOrderLine> insuranceLineList = sapMobyMapService.getConfirmedInsuranceLine(body.getFlatTradeOrderLineList());
        if (null == insuranceLineList || insuranceLineList.size() == 0)
            throw new SapBizException("确认保险, 没有 已确认 的保险订单行" + mobyTradeOrderId);

        // 复用 SapLoanConfirmedRequestBody
        SapLoanConfirmedRequestBody sapBody = new SapLoanConfirmedRequestBody();
        BeanUtils.copyProperties(oldRecord, sapBody);
        sapBody.setOperatorId(insuranceLineList.get(0).getOperatorId());

        for (MobyOrderLine line : insuranceLineList) {
            createFromEachMobyLine(body, sapBody, line);
        }

        return sapBody;
    }

    /** 组装请求体: 修改顾问 */
    public SapOrderRequestBody assembleConsultChanged(MobyEventBody body) throws SapBizException {
        SapAdapterOrder oldRecord = assureMobyTradeOrderExist(body);

        // 复用 SapLoanConfirmedRequestBody
        SapLoanConfirmedRequestBody sapBody = new SapLoanConfirmedRequestBody();
        BeanUtils.copyProperties(oldRecord, sapBody);
        sapBody.setScCode(body.getMobyTradeOrder().getScCode());

        return sapBody;
    }

    /** 组装请求体: 精品修改 */
    public SapOrderRequestBody assembleBoutiqueChanged(MobyEventBody body) throws SapBizException {
        SapAdapterOrder oldRecord = assureMobyTradeOrderExist(body);
        String mobyTradeOrderId = body.getMobyTradeOrder().getId();

        SapLoanConfirmedRequestBody sapBody = new SapLoanConfirmedRequestBody();
        BeanUtils.copyProperties(oldRecord, sapBody);

        /* 找到2个队列: 1是需要新增的, 2是需要删除的 */

        /* currentList 是最新的精品订单行 */
        List<MobyOrderLine> currentList = sapMobyMapService.getBoutiqueLine(body.getFlatTradeOrderLineList());
        List<String> currentIdList = currentList.stream()
                .map(MobyOrderLine::getId)
                .collect(Collectors.toList());
        if (currentList.size() == 0)
            throw new SapBizException("修改精品, 但是精品行无数据 moby订单Id=" + mobyTradeOrderId);

        /* preIdList = 以前存储的精品行记录 */
        List<SapAdapterOrderLine> preList = lineMapper.listByMobyOrder(mobyTradeOrderId);
        if (null == preList) preList = new ArrayList<>(0);
        List<String> preIdList = sapMobyMapService
                .getBoutiqueLineFromRecord(preList)
                .stream()
                .map(SapAdapterOrderLine::getMobyLineId)
                .collect(Collectors.toList());

        /* 对于增项处理 */
        List<String> toAdd = listSub(currentIdList, preIdList);
        if (toAdd.size() > 0) {
            List<MobyOrderLine> addLineList = currentList.stream()
                    .filter(mobyOrderLine -> toAdd.indexOf(mobyOrderLine.getId()) != -1)
                    .collect(Collectors.toList());
            for (MobyOrderLine mobyOrderLine : addLineList) {
                createFromEachMobyLine(body, sapBody, mobyOrderLine);
            }
        }

        List<String> toDel = listSub(preIdList, currentIdList);
        if (toDel.size() > 0) {
            List<SapAdapterOrderLine> deleteLineList = preList.stream()
                    .filter(sapAdapterOrderLine -> toDel.indexOf(sapAdapterOrderLine.getMobyLineId()) != -1)
                    .collect(Collectors.toList());
            for (SapAdapterOrderLine oldLine : deleteLineList) {
                removeEach(sapBody, oldLine);
            }
        }
        if (toAdd.size() + toDel.size() == 0) {
            throw new SapBizException("修改精品, 但没有需要新增 或 删除的行 moby订单Id=" + mobyTradeOrderId);
        }

        return sapBody;
    }

    /** 组装请求体: 结算 */
    public SapOrderRequestBody assembleBilling(MobyEventBody body) throws SapBizException {
        SapAdapterOrder sapAdapterOrder = assureMobyTradeOrderExist(body);
        // TODO 优化项, 对于有车的订单, 检测有车才能 billing

        List<SapAdapterFund> fundList = fundMapper.listByTradeOrder(body.getMobyTradeOrder().getId());
        List<SapAdapterFund> billFundList = fundList.stream()
                .filter(sapAdapterFund -> sapAdapterFund.isTakePartInBilling() && !sapAdapterFund.isRefund())
                .collect(Collectors.toList());

        SapBillingRequestBody requestBody = new SapBillingRequestBody();
        BeanUtils.copyProperties(sapAdapterOrder, requestBody);
        // operatorId
        requestBody.setOperatorId(body.getMobyTradeOrder().getBillingBy());

        billFundList.forEach(fund -> requestBody.addSapBillRecord(fund.getSapReceiptNo(), fund.getPayMoney()));
        return requestBody;
    }

    /** 组装请求体: 出库 */
    public SapOrderRequestBody assembleStockOut(MobyEventBody body) throws SapBizException {
        String mobyTradeOrderId = body.getMobyTradeOrder().getId();
        SapAdapterOrder oldRecord = assureMobyTradeOrderExist(body);

        SapStockOutRequestBody sapBody = new SapStockOutRequestBody();
        BeanUtils.copyProperties(oldRecord, sapBody);

        StockOut stockOut = body.getStockOut();
        String stockoutDate = stockOut.getStockOutDate();
        if (null == stockoutDate)
            throw new SapBizException("出库操作, 出库时间为null, moby订单Id=" + mobyTradeOrderId);

        List<String> mobyLineList = stockOut.getMobyLineIdList();
        sapBody.setDeliveryDate(DateFormatConvert.getDate(stockoutDate));

        if (null == mobyLineList || 0 == mobyLineList.size()) {
            throw new SapBizException("出库操作, 但是没有任何东西出库, moby订单Id=" + mobyTradeOrderId);
        }

        // 查询 mobyLineId => sapLineId
        List<SapAdapterOrderLine> savedLineList = lineMapper.listByMobyOrder(mobyTradeOrderId);
        Map<String, SapAdapterOrderLine> cache = new HashMap<>(mobyLineList.size());
        savedLineList.forEach(sapLine -> cache.put(sapLine.getMobyLineId(), sapLine));

        mobyLineList.forEach(mobyLineId -> {
            SapOrderLine sapOrderLine = new SapOrderLine();
            SapAdapterOrderLine sapAdapterOrderLine = cache.get(mobyLineId);
            sapOrderLine.setSapLineNo(sapAdapterOrderLine.getSapLineNo());
            sapBody.addLineItem(sapOrderLine);
        });

        return sapBody;
    }

    /** 组装请求体: 采购一个订单行中的项目 */
    public SapOrderRequestBody assemblePurchaseItem(String mobyTradeOrderId, String mobyLineId) throws SapBizException {
        SapAdapterOrder sapAdapterOrder = assureMobyTradeOrderExist(mobyTradeOrderId);

        List<SapAdapterOrderLine> lineList = lineMapper.listByMobyOrder(mobyTradeOrderId);
        if (null == lineList || 0 == lineList.size())
            throw new SapBizException("采购操作, 没有订单号, moby订单Id=" + mobyTradeOrderId);

        SapAdapterOrderLine targetLine = null;
        for (SapAdapterOrderLine aLine : lineList) {
            if (aLine.getMobyLineId().equals(mobyLineId)) {
                targetLine = aLine;
                break;
            }
        }
        if (null == targetLine)
            throw new SapBizException("采购操作, 找不到对应的订单行, moby订单Id=" + mobyLineId + ", moby订单Id=" + mobyTradeOrderId);

        SapPurchaseRequestBody sapBody = new SapPurchaseRequestBody();
        BeanUtils.copyProperties(sapAdapterOrder, sapBody);
        SapOrderLine sapOrderLine = new SapOrderLine();
        sapOrderLine.setItemCatalog(targetLine.getItCat());
        sapOrderLine.setSapLineNo(targetLine.getSapLineNo());
        sapOrderLine.setToBuy(SapOrderLine.AUTO_PURCHASE_YES);

        sapBody.addSapOrderLine(sapOrderLine);

        return sapBody;
    }

    /** 组装请求体: 提供精品/保养, 可以同时提供 */
    public SapOrderRequestBody assembleOfferBoutiqueOrMaintain(MobyEventBody body) throws SapBizException {
        SapAdapterOrder oldRecord = assureMobyTradeOrderExist(body);
        String mobyTradeOrderId = body.getMobyTradeOrder().getId();

        SapLoanConfirmedRequestBody sapBody = new SapLoanConfirmedRequestBody();
        BeanUtils.copyProperties(oldRecord, sapBody);

        List<MobyOrderLine> maintainList = sapMobyMapService.getMaintainLine(body.getFlatTradeOrderLineList());
        List<MobyOrderLine> boutiqueList = sapMobyMapService.getBoutiqueLine(body.getFlatTradeOrderLineList());

        /* TODO 操作人 */
        // sapBody.setOperatorId(insuranceLineList.get(0).getOperatorId());
        int totalChange = 0;
        totalChange += null == maintainList ? 0 : maintainList.size();
        totalChange += null == boutiqueList ? 0 : boutiqueList.size();
        if (0 == totalChange) {
            throw new SapBizException("提供精品保养, 但是没有相关的 精品/保养 订单行");
        }

        List<SapAdapterOrderLine> oldLineList = lineMapper.listByMobyOrder(mobyTradeOrderId);
        Map<String, SapAdapterOrderLine> cache4OldLine = new HashMap<>(oldLineList.size());
        oldLineList.forEach(oldLine -> cache4OldLine.put(oldLine.getMobyLineId(), oldLine));

        /* 处理保养 */
        if (null != maintainList && 0 != maintainList.size()) {
            /* 过滤已经保存 */
            for (MobyOrderLine line : maintainList) {
                if (null != cache4OldLine.get(line.getId())) {
                    logger.warn("已存在的保养行 项目, 跳过");
                    continue;
                }
                createMaintainFromEachMobyLine(body, sapBody, line);
            }
        }

        /* 处理精品 */
        if (null != boutiqueList && 0 != boutiqueList.size()) {
            /* 过滤已经保存 */
            for (MobyOrderLine line : boutiqueList) {
                if (null != cache4OldLine.get(line.getId())) {
                    logger.warn("已存在的精品行 项目, 跳过");
                    continue;
                }
                createFromEachMobyLine(body, sapBody, line);
            }
        }

        return sapBody;
    }

    /** 根据每个 mobyLine 创建 sap 订单行 */
    private void createFromEachMobyLine(MobyEventBody body, SapOrderRequestBody sapBody, MobyOrderLine mobyLine) throws SapBizException {
        SapOrderLine sapLine = new SapOrderLine();
        sapLine.setExternalLineNo(mobyLine.getId());

        /* 如果是车辆, 则是 物料填写车型代码 */
        if (sapMobyMapService.isVehicleLine(mobyLine)) {
            sapLine.setMaterialNo(mobyLine.getVehicleModelCode());
        } else {
            sapLine.setMaterialNo(mobyLine.getMaterialCode());
        }

        /* 如果是赠送类型, 则 价格=0 */
        if (sapMobyMapService.isLineFree(mobyLine)) {
            sapLine.setPrice(SapMapConst.PRICE_FREE);
        } else {
            sapLine.setPrice(mobyLine.getPriceMoney());
        }

        sapLine.setQuantity(mobyLine.getQuantity());
        sapLine.setItemCatalog(getSapItemCatalog(body, mobyLine));

        /* 设置库位, 精品已定要有库位 */
        if (StringUtil.isNullorEmpty(mobyLine.getWarehouseCode())) {
            if (sapMobyMapService.isBoutiqueLine(mobyLine)) throw new SapBizException("精品必须有库位信息");
            sapLine.setWarehouseCode("");
        } else {
            sapLine.setWarehouseCode(mobyLine.getWarehouseCode());
        }

        /* 设置 change = 新增 */
        sapLine.setChangeType(SapOrderLine.CHANGE_TYPE_ADD);

        /* 自动采购 */
        String autoBuyFlag = dictService.getSapValueByMoby(SapDictType.AUTO_PURCHASE_FLAG, mobyLine.getAutoPurchase());
        if (StringUtil.isNullorEmpty(autoBuyFlag)) {
            // 设置默认值
            autoBuyFlag = SapOrderLine.AUTO_PURCHASE_YES;
        }
        sapLine.setToBuy(autoBuyFlag);

        sapBody.addLineItem(sapLine);
    }

    /**
     * 行项目类别
     * 1. 先从 productType中获取,(服务/保险/保养)
     * 2. 没有, 再从 material->itcat表中获取
     */
    private String getSapItemCatalog(MobyEventBody body, MobyOrderLine mobyLine) throws SapBizException {
        String sapItemCat = dictService.getSapValueByMoby(SapDictType.PRODUCT_TYPE_ITCAT, mobyLine.getProductType());
        if (null != sapItemCat) return sapItemCat;

        logger.warn("无法根据【字典表】查询行项目类别, 订单类型={}", mobyLine.getProductType());
        logger.info("使用【物料对照表】查询行项目类别");
        String orderSenseName = body.getMobyTradeOrder().getOrderType();
        Material2ItCat material2ItCat = material2ItCatMapper.findOneByName(orderSenseName, mobyLine.getProductType(), mobyLine.getMaterialCode());
        if (null != material2ItCat) {
            sapItemCat = material2ItCat.getSapItcat();
        } else {
            String errMsg = "无法从【物料对照表】中，找到对应的【行项目类别】"
                    + ", orderSenseName=" + orderSenseName
                    + ", lineProductType=" + mobyLine.getProductType()
                    + ", materialCode=" + mobyLine.getMaterialCode();
            logger.error(errMsg);

            /* 插入到 数据库, 待补全 */
            material2ItCatMapper.insert(Material2ItCatFactory.lostRecordOfMaterial2Itcat(body, mobyLine));

            throw new SapBizException(errMsg);
        }
        return sapItemCat;
    }

    /** 根据每个 mobyLine 创建 sap 保养订单行, 保养订单行很特别 */
    private void createMaintainFromEachMobyLine(MobyEventBody body, SapOrderRequestBody sapBody, MobyOrderLine mobyLine) throws SapBizException {
        if (!sapMobyMapService.isMaintainLine(mobyLine))
            throw new SapBizException("创建保养行,但是mobyLine不是保养行");

        SapOrderLine sapLine = new SapOrderLine();
        sapLine.setExternalLineNo(mobyLine.getId());
        sapLine.setMaterialNo(mobyLine.getMaterialCode());

        /* 不需要自动采购 */
        sapLine.setToBuy("");
        /* 如果是赠送类型, 则 价格=0 */
        if (sapMobyMapService.isLineFree(mobyLine)) {
            sapLine.setPrice(SapMapConst.PRICE_FREE);
        } else {
            sapLine.setPrice(mobyLine.getPriceMoney());
        }
        sapLine.setItemCatalog(getSapItemCatalog(body, mobyLine));
        sapLine.setQuantity(mobyLine.getQuantity());
        sapLine.setWarehouseCode("");
        sapLine.setChangeType(SapOrderLine.CHANGE_TYPE_ADD);

        /* coupon相关 */
        sapLine.setCouponKeyword(mobyLine.getMaterialCode());
        sapLine.setCouponId(mobyLine.getBundleSkuId());
        sapLine.setCouponDesc(mobyLine.getDescription());
        if (sapMobyMapService.isLineFree(mobyLine)) {
            sapLine.setCouponType(SapMapConst.COUPON_TYPE_GOODS_OR_SERVICE);
        } else {
            sapLine.setCouponType(SapMapConst.COUPON_TYPE_DEPOSIT);
        }
        sapLine.setCouponZType(SapMapConst.COUPON_ZTYPE_ITEM);
        sapLine.setCouponCreditMoney(mobyLine.getPriceMoney());
        if (sapMobyMapService.isLineFree(mobyLine)) {
            sapLine.setCouponAquiredMethod(SapMapConst.COUPON_ACQUIRE_TYPE_GIFT);
        } else {
            sapLine.setCouponAquiredMethod(SapMapConst.COUPON_ACQUIRE_TYPE_BUY);
        }

        sapBody.addLineItem(sapLine);
    }

    /** 移除行项目 */
    private void removeEach(SapOrderRequestBody sapBody, SapAdapterOrderLine oldLine) {
        SapOrderLine sapLine = new SapOrderLine();
        sapLine.setExternalLineNo(oldLine.getMobyLineId());
        sapLine.setSapLineNo(oldLine.getSapLineNo());
        sapLine.setChangeType(SapOrderLine.CHANGE_TYPE_DELETE);

        sapBody.addLineItem(sapLine);
    }

    private SapAdapterOrder assureMobyTradeOrderExist(MobyEventBody body) throws SapBizException {
        if (body == null)
            throw new SapBizException("请求参数null");
        return assureMobyTradeOrderExist(body.getMobyTradeOrder().getId());
    }

    private SapAdapterOrder assureMobyTradeOrderExist(String mobyTradeOrderId) throws SapBizException {
        SapAdapterOrder oldRecord = orderMapper.findOneByMobyOrder(mobyTradeOrderId);
        if (null == oldRecord)
            throw new SapBizException("确认保险, 但是 对接中心没有此订单的同步记录 moby订单Id=" + mobyTradeOrderId);

        return oldRecord;
    }

    // 集合相减, TODO 找个工具类实现
    // 找到 在 list1中, 而又不在list2中的
    private List<String> listSub(List<String> list1, List<String> list2) {
        if (null == list2 || 0 == list2.size()) return list1;
        Set<String> list2Set = new HashSet<String>(list2);

        return list1.stream()
                .filter(s -> !list2Set.contains(s))
                .collect(Collectors.toList());
    }

}
